﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

using System.Text.RegularExpressions;

namespace KingOfCSharp.iHunter.Plugins.BBS
{
    public class BbsHost
    {
        public string HostAddress
        {
            get;
            private set;
        }

        public string Username
        {
            get;
            private set;
        }

        public string Password
        {
            get;
            private set;
        }

        public int Port
        {
            get;
            private set;
        }

        public ConnectionType ConnectionType
        {
            get;
            private set;
        }

        public HostType HostType
        {
            get;
            private set;
        }

        public BbsHost(string addr, string username, string pwd, int port, ConnectionType conType, HostType hostType)
        {
            this.HostAddress = addr;
            this.Username = username;
            this.Password = pwd;
            this.Port = port;
            this.ConnectionType = conType;
            this.HostType = hostType;
        }
    }

    public class Post : IComparable<Post>
    {
        private static Regex regex_att = new Regex(@"附\w: ([^ ]+) \(([0-9\.]+) (\w+)\) 链接:");

        public string Author
        {
            get;
            set;
        }

        public string Board
        {
            get;
            set;
        }

        public string Title
        {
            get;
            set;
        }

        public BbsHost Host
        {
            get;
            set;
        }

        public DateTime PostTime
        {
            get;
            set;
        }

        public string PlainText
        {
            get;
            set;
        }

        public string HtmlText
        {
            get;
            set;
        }

        public IMessage ToMessage()
        {
            string header = string.Format(
                "Board: {0}\nAuthor: {1}\nTime: {2}",
                this.Board,
                this.Author,
                this.PostTime
                );
            Message msg = new Message(Guid.Empty, header.GetHashCode());

            msg.Author = this.Author;
            msg.Title = this.Title;
            msg.UpdateTime = msg.PublishTime = this.PostTime;
            msg.Content = this.HtmlText;

			msg.Category = this.Board;
            msg.CustomFields["PlainText"] = this.PlainText;

            msg.ViewerGuid = new Guid("751B6808-5676-43b6-B9B7-B167CF9743F4");
            msg.EditorGuid = BbsItemEditorProvider.Guid;
            GetAttachments(msg);

            return msg;
        }

        private void GetAttachments(IMessage msg)
        {
            string[] lines = this.PlainText.Split(
                new char[]{'\n'},
                StringSplitOptions.RemoveEmptyEntries
                );

            int i = lines.Length - 1;

            while (i >= 0 && !(lines[i] != null && lines[i].StartsWith("http://")))
                i--;

            if (i < 0 || (i >= 0 && lines[i] == null))
                return;

            bool hasAtt = true;            

            if (hasAtt)
            {
                while (i >= 1 && lines[i].StartsWith("http://"))
                {
                    Match m = regex_att.Match(lines[i-1]);
                    if (!m.Success)
                    {
                        i-=2;
                        continue;
                    }

					string descrip = "File";

                    string filename = m.Groups[1].Value;
                    string type = "";
                    int ind = filename.LastIndexOf(".");
					if (ind >= 0 && ind < filename.Length - 1)
					{
						type = filename.Substring(ind + 1);

						if (type.Equals("jpg") || type.Equals("jpeg") ||
							type.Equals("png") || type.Equals("bmp") ||
							type.Equals("gif"))
							descrip = "Pic";
					}

                    double size = 0;
                    Double.TryParse(m.Groups[2].Value, out size);

                    if ("KB".Equals(m.Groups[3].Value))
                        size *= 1024;
                    else if ("MB".Equals(m.Groups[3].Value))
                        size *= (1024*1024);

                    long filesize = Convert.ToInt64(size);

					
					

                    Attachment att = new Attachment(filename, type, filesize, lines[i].Trim(), descrip);
                    msg.Attachments.Add(att);

                    i -= 2;
                }
            }
        }

        public Post()
        {

        }

        public Post(IMessage msg)
        {
            this.Author = msg.Author;
            this.HtmlText = msg.Content;
            this.PlainText = msg.CustomFields["PlainText"];
            this.PostTime = msg.PublishTime;
            this.Title = msg.Title;
			this.Board = msg.Category;
        }

		#region IComparable<Post> Members

		public int CompareTo(Post other)
		{
			int comp = this.PostTime.CompareTo(other.PostTime);
			if (comp != 0)
				return comp;

			comp = this.Author.CompareTo(other.Author);
			if (comp != 0)
				return comp;

			comp = this.Board.CompareTo(other.Board);
			return comp;
		}

		#endregion
	}

    public class Thread
    {
        public Post MainPost
        {
            get;
            private set;
        }

        public List<Post> Replies
        {
            get;
            private set;
        }
    }

    public class Mail 
    {
        public static string MailCategory
        {
            get
            {
                return "BBS Mail";
            }
        }

        public string Sender
        {
            get;
            set;
        }

        public string Receiver
        {
            get;
            set;
        }

        public DateTime SendTime
        {
            get;
            set;
        }

        public string Title
        {
            get;
            set;
        }

        public MailType Type
        {
            get;
            protected set;
        }

        public string PlainText
        {
            get;
            set;
        }

        public string HtmlText
        {
            get;
            set;
        }

        public BbsHost Host
        {
            get;
            set;
        }

        public Mail(MailType type)
        {
            this.Type = type;
        }

        public IMessage ToMessage()
        {
            string header = string.Format(
                "Sender: {0}\nReceiver: {1}\nTitle: {2}\nTime: {3}",
                this.Sender,
                this.Receiver,
                this.Title,
                this.SendTime
                );
            Message msg = new Message(Guid.Empty, header.GetHashCode());

            msg.Author = this.Sender;
            msg.Content = this.HtmlText;
            msg.UpdateTime = msg.PublishTime = this.SendTime;
            msg.Title = this.Title;

			msg.Category = Mail.MailCategory;

            msg.Receiver = this.Receiver;

            msg.CustomFields["PlainText"] = this.PlainText;
            string mType = "NormalMail";
            if (this.Type == MailType.Message)
                mType = "Message";
            else if (this.Type == MailType.ForwardedPost)
                mType = "ForwardedPost";
            msg.CustomFields["MailType"] = mType;

            msg.ViewerGuid = new Guid("751B6808-5676-43b6-B9B7-B167CF9743F4");
            msg.EditorGuid = BbsItemEditorProvider.Guid;

            return msg;
        }

        public Mail()
        {

        }

        public Mail(IMessage msg)
        {
            this.Sender = msg.Author;
            this.HtmlText = msg.Content;
            if (msg.CustomFields.ContainsKey("PlainText"))
                this.PlainText = msg.CustomFields["PlainText"];
            this.SendTime = msg.PublishTime;
            this.Title = msg.Title;
            this.Receiver = msg.Receiver;

            string mType = msg.CustomFields["MailType"];

            if (mType.Equals("NormalMail"))
                this.Type = MailType.NormalMail;
            else if (mType.Equals("ForwardedPost"))
                this.Type = MailType.ForwardedPost;
            else
                this.Type = MailType.Message;
        }

	}

    public enum MailType
    {
        NormalMail,
        ForwardedPost,
        Message
    }

    /// <summary>
    /// Types of connection
    /// </summary>
    public enum ConnectionType
    {
        Telnet,
        SSH1,
        SSH2,
    }

    /// <summary>
    /// A static class dealing with characters, especially control characters
    /// </summary>
    public static class Character
    {
        /// <summary>
        /// Carriage return (\r)
        /// </summary>
        public const char CR = (char)13;

        /// <summary>
        /// Line feed (\n)
        /// </summary>
        public const char LF = (char)10;

        /// <summary>
        /// ESC control char
        /// </summary>
        public const char ESC = (char)27;

        public static readonly string DoubleESC = new string(ESC, 2);

        /// <summary>
        /// NUL char
        /// </summary>
        public const char NUL = (char)0;

        /// <summary>
        /// A string represent a space in Html code
        /// </summary>
        public const string HtmlSpace = "&nbsp;";

        /// <summary>
        /// A string represent a LessThan in Html code
        /// </summary>
        public const string HtmlLT = "&lt;";

        /// <summary>
        /// A string represent a GreaterThan in Html code
        /// </summary>
        public const string HtmlGT = "&gt;";

        /// <summary>
        /// A string represent a & in Html code
        /// </summary>
        public const string HtmlAnd = "&amp;";

        /// <summary>
        /// A string represent a quot in Html code
        /// </summary>
        public const string HtmlQuot = "&quot;";

        /// <summary>
        /// "\r\n"
        /// </summary>
        public const string CRLF = "\r\n";

        /// <summary>
        /// Tells whether the char needs two bytes to store
        /// </summary>
        /// <param name="ch">The char</param>
        /// <returns>Whether the char needs two bytes to store</returns>
        public static bool NeedTwoByte(char ch)
        {
            return (ch >= 0x80);
        }

        private static KeysConverter keyConverter = new KeysConverter();

        public static int GetStringLengthInTerm(string str)
        {
            int len = 0;
            foreach (char ch in str)
            {
                if (NeedTwoByte(ch))
                    len += 2;
                else
                    len++;
            }

            return len;
        }

        /// <summary>
        /// Get the control string from keys pressed
        /// </summary>
        /// <param name="key">The key pressed</param>
        /// <param name="modifier">The modifier, including CTRL,ATL and SHIFT</param>
        /// <returns>The string of the control command</returns>
        public static string GetControlString(Keys key, Keys modifier)
        {
            if (modifier == Keys.Control)
            {
                string k = keyConverter.ConvertToString(key);

                if (null != k && k.Length == 1)
                {
                    char ch = k[0];
                    if ('A' <= ch && ch <= 'Z')
                    {
                        char cKey = (char)(ch - 'A' + 1);
                        return new string(cKey, 1);
                    }
                }
            }
            else if (modifier == Keys.None)
            {
                switch (key)
                {
                    case Keys.Enter:
                        return "\x0D";

                    case Keys.Home:
                        return "\x1B[1~";

                    case Keys.Insert:
                        return "\x1B[2~";

                    case Keys.Delete:
                        return "\x1B[3~";

                    case Keys.End:
                        return "\x1B[4~";

                    case Keys.PageUp:
                        return "\x1B[5~";

                    case Keys.PageDown:
                        return "\x1B[6~";

                    case Keys.Up:
                        return "\x1B[A";

                    case Keys.Down:
                        return "\x1B[B";

                    case Keys.Right:
                        return "\x1B[C";

                    case Keys.Left:
                        return "\x1B[D";

                }

                string k = keyConverter.ConvertToString(key);

                if (null != k && k.Length == 1)
                {
                    return k;
                }
            }

            return "";
        }
    }
}
